const bcrypt = require('bcryptjs');
const User = require('../models/User');
const jwt = require('../utils/jwt');
const logger = require('../utils/logger');
const blockchainService = require('../services/blockchainService');
const {
  successResponse,
  errorResponse,
  validationErrorResponse,
  unauthorizedResponse,
  conflictResponse,
  internalErrorResponse
} = require('../utils/response');

/**
 * 用户注册
 */
const register = async (req, res) => {
  try {
    const { username, email, password, phone, role, profile } = req.body;

    // 检查用户是否已存在
    const existingUser = await User.findOne({
      $or: [
        { email: email.toLowerCase() },
        { username }
      ]
    });

    if (existingUser) {
      if (existingUser.email === email.toLowerCase()) {
        return conflictResponse(res, '邮箱已被注册');
      }
      if (existingUser.username === username) {
        return conflictResponse(res, '用户名已被使用');
      }
    }

    // 生成区块链地址（演示用）
    const blockchainAddress = blockchainService.generateRandomAddress();

    // 创建新用户
    const userData = {
      address: blockchainAddress,
      username,
      email: email.toLowerCase(),
      password,
      phone,
      role,
      profile: profile || {}
    };

    const user = new User(userData);
    await user.save();

    // 尝试在区块链上注册用户
    try {
      const blockchainResult = await blockchainService.registerUser(
        blockchainAddress,
        role
      );
      
      if (blockchainResult.success) {
        logger.info('用户区块链注册成功:', {
          userId: user._id,
          address: blockchainAddress,
          txHash: blockchainResult.txHash
        });
      }
    } catch (blockchainError) {
      logger.warn('区块链注册失败，但用户已创建:', {
        userId: user._id,
        error: blockchainError.message
      });
    }

    // 生成令牌对
    const tokens = jwt.generateTokenPair(user);

    // 保存刷新令牌到数据库
    user.refreshTokens.push({
      token: tokens.refreshToken,
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天
    });
    await user.save();

    // 记录用户注册日志
    logger.info('用户注册成功:', {
      userId: user._id,
      username: user.username,
      email: user.email,
      role: user.role,
      ip: req.ip
    });

    // 返回用户信息（不包含密码）
    const userResponse = user.toJSON();
    delete userResponse.password;
    delete userResponse.refreshTokens;

    return successResponse(res, {
      user: userResponse,
      tokens
    }, '注册成功', 201);

  } catch (error) {
    logger.error('用户注册失败:', {
      error: error.message,
      stack: error.stack,
      requestBody: req.body
    });

    if (error.code === 11000) {
      return conflictResponse(res, '用户信息已存在');
    }

    return internalErrorResponse(res, error);
  }
};

/**
 * 用户登录
 */
const login = async (req, res) => {
  try {
    const { email, password, rememberMe = false } = req.body;

    // 查找用户
    const user = await User.findByEmail(email.toLowerCase());
    if (!user) {
      return unauthorizedResponse(res, '邮箱或密码错误');
    }

    // 检查账户状态
    if (user.status !== 'active') {
      return unauthorizedResponse(res, '账户已被禁用');
    }

    // 检查账户是否被锁定
    if (user.isAccountLocked()) {
      return unauthorizedResponse(res, '账户已被锁定，请稍后再试');
    }

    // 验证密码
    const isPasswordValid = await user.comparePassword(password);
    if (!isPasswordValid) {
      // 记录失败尝试
      user.loginAttempts = user.loginAttempts + 1;
      user.lastFailedLogin = new Date();

      // 如果失败次数过多，锁定账户
      if (user.loginAttempts >= 5) {
        user.accountLockedUntil = new Date(Date.now() + 30 * 60 * 1000); // 锁定30分钟
      }

      await user.save();

      logger.warn('用户登录失败:', {
        email: email.toLowerCase(),
        ip: req.ip,
        attempts: user.loginAttempts
      });

      return unauthorizedResponse(res, '邮箱或密码错误');
    }

    // 登录成功，重置失败记录
    user.loginAttempts = 0;
    user.accountLockedUntil = undefined;
    user.lastFailedLogin = undefined;

    // 生成令牌对
    const expiresIn = rememberMe ? '30d' : '24h';
    const tokens = jwt.generateTokenPair(user);

    // 清理过期的刷新令牌
    user.refreshTokens = user.refreshTokens.filter(
      tokenObj => tokenObj.expiresAt > new Date()
    );

    // 保存新的刷新令牌
    const refreshTokenExpiry = rememberMe 
      ? new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // 30天
      : new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);  // 7天

    user.refreshTokens.push({
      token: tokens.refreshToken,
      expiresAt: refreshTokenExpiry
    });

    // 更新最后登录时间
    user.updateLastLogin();
    await user.save();

    // 记录登录日志
    logger.info('用户登录成功:', {
      userId: user._id,
      username: user.username,
      email: user.email,
      ip: req.ip,
      userAgent: req.get('User-Agent')
    });

    // 返回用户信息（不包含敏感数据）
    const userResponse = user.toJSON();
    delete userResponse.password;
    delete userResponse.refreshTokens;

    return successResponse(res, {
      user: userResponse,
      tokens: {
        ...tokens,
        expiresIn
      }
    }, '登录成功');

  } catch (error) {
    logger.error('用户登录失败:', {
      error: error.message,
      stack: error.stack,
      email: req.body.email
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 刷新令牌
 */
const refreshToken = async (req, res) => {
  try {
    const { refreshToken } = req.body;

    if (!refreshToken) {
      return unauthorizedResponse(res, '刷新令牌缺失');
    }

    // 验证刷新令牌
    let decoded;
    try {
      decoded = jwt.verifyRefreshToken(refreshToken);
    } catch (error) {
      return unauthorizedResponse(res, '无效的刷新令牌');
    }

    // 查找用户和刷新令牌
    const user = await User.findById(decoded.userId);
    if (!user) {
      return unauthorizedResponse(res, '用户不存在');
    }

    // 检查刷新令牌是否在数据库中
    const tokenIndex = user.refreshTokens.findIndex(
      tokenObj => tokenObj.token === refreshToken && tokenObj.expiresAt > new Date()
    );

    if (tokenIndex === -1) {
      return unauthorizedResponse(res, '刷新令牌无效或已过期');
    }

    // 生成新的令牌对
    const tokens = jwt.generateTokenPair(user);

    // 移除旧的刷新令牌，添加新的刷新令牌
    user.refreshTokens.splice(tokenIndex, 1);
    user.refreshTokens.push({
      token: tokens.refreshToken,
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天
    });

    await user.save();

    logger.info('令牌刷新成功:', {
      userId: user._id,
      ip: req.ip
    });

    return successResponse(res, { tokens }, '令牌刷新成功');

  } catch (error) {
    logger.error('令牌刷新失败:', {
      error: error.message,
      stack: error.stack
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 用户登出
 */
const logout = async (req, res) => {
  try {
    const user = req.user;
    const { refreshToken } = req.body;

    if (refreshToken) {
      // 从数据库中移除指定的刷新令牌
      user.refreshTokens = user.refreshTokens.filter(
        tokenObj => tokenObj.token !== refreshToken
      );
    } else {
      // 如果没有提供刷新令牌，清除所有刷新令牌
      user.refreshTokens = [];
    }

    await user.save();

    logger.info('用户登出成功:', {
      userId: user._id,
      ip: req.ip
    });

    return successResponse(res, null, '登出成功');

  } catch (error) {
    logger.error('用户登出失败:', {
      error: error.message,
      stack: error.stack,
      userId: req.user?._id
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 获取当前用户信息
 */
const getCurrentUser = async (req, res) => {
  try {
    const user = req.user;

    // 返回用户信息（不包含敏感数据）
    const userResponse = user.toJSON();
    delete userResponse.password;
    delete userResponse.refreshTokens;

    return successResponse(res, { user: userResponse }, '获取用户信息成功');

  } catch (error) {
    logger.error('获取用户信息失败:', {
      error: error.message,
      stack: error.stack,
      userId: req.user?._id
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 修改密码
 */
const changePassword = async (req, res) => {
  try {
    const { currentPassword, newPassword } = req.body;
    const user = req.user;

    // 验证当前密码
    const isCurrentPasswordValid = await user.comparePassword(currentPassword);
    if (!isCurrentPasswordValid) {
      return unauthorizedResponse(res, '当前密码错误');
    }

    // 检查新密码是否与当前密码相同
    const isSamePassword = await user.comparePassword(newPassword);
    if (isSamePassword) {
      return errorResponse(res, '新密码不能与当前密码相同', 400);
    }

    // 更新密码
    user.password = newPassword;
    
    // 清除所有刷新令牌（强制重新登录）
    user.refreshTokens = [];
    
    await user.save();

    logger.info('用户修改密码成功:', {
      userId: user._id,
      ip: req.ip
    });

    return successResponse(res, null, '密码修改成功，请重新登录');

  } catch (error) {
    logger.error('修改密码失败:', {
      error: error.message,
      stack: error.stack,
      userId: req.user?._id
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 忘记密码 - 发送重置链接
 */
const forgotPassword = async (req, res) => {
  try {
    const { email } = req.body;

    const user = await User.findByEmail(email.toLowerCase());
    if (!user) {
      // 为了安全，即使用户不存在也返回成功
      return successResponse(res, null, '如果邮箱存在，重置链接已发送');
    }

    // 生成重置令牌
    const resetToken = jwt.generateAccessToken(
      { userId: user._id, purpose: 'password-reset' },
      '1h'
    );

    // 保存重置令牌到数据库
    user.passwordResetToken = resetToken;
    user.passwordResetExpires = new Date(Date.now() + 60 * 60 * 1000); // 1小时
    await user.save();

    logger.info('密码重置令牌生成成功:', {
      userId: user._id,
      email: user.email,
      ip: req.ip
    });

    // 这里应该发送邮件，暂时返回令牌（实际生产环境中不应该返回）
    const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${resetToken}`;

    return successResponse(res, {
      message: '重置链接已生成',
      resetUrl: process.env.NODE_ENV === 'development' ? resetUrl : undefined
    }, '如果邮箱存在，重置链接已发送');

  } catch (error) {
    logger.error('发送密码重置链接失败:', {
      error: error.message,
      stack: error.stack,
      email: req.body.email
    });

    return internalErrorResponse(res, error);
  }
};

/**
 * 重置密码
 */
const resetPassword = async (req, res) => {
  try {
    const { token, newPassword } = req.body;

    // 验证重置令牌
    let decoded;
    try {
      decoded = jwt.verifyAccessToken(token);
    } catch (error) {
      return unauthorizedResponse(res, '无效或已过期的重置令牌');
    }

    if (decoded.purpose !== 'password-reset') {
      return unauthorizedResponse(res, '无效的重置令牌');
    }

    // 查找用户
    const user = await User.findById(decoded.userId);
    if (!user || user.passwordResetToken !== token) {
      return unauthorizedResponse(res, '无效或已过期的重置令牌');
    }

    // 检查令牌是否过期
    if (user.passwordResetExpires < new Date()) {
      return unauthorizedResponse(res, '重置令牌已过期');
    }

    // 更新密码
    user.password = newPassword;
    user.passwordResetToken = undefined;
    user.passwordResetExpires = undefined;
    
    // 清除所有刷新令牌
    user.refreshTokens = [];
    
    await user.save();

    logger.info('密码重置成功:', {
      userId: user._id,
      ip: req.ip
    });

    return successResponse(res, null, '密码重置成功，请使用新密码登录');

  } catch (error) {
    logger.error('密码重置失败:', {
      error: error.message,
      stack: error.stack
    });

    return internalErrorResponse(res, error);
  }
};

module.exports = {
  register,
  login,
  refreshToken,
  logout,
  getCurrentUser,
  changePassword,
  forgotPassword,
  resetPassword
};